/*
 * @Author: 姚潘涛
 * @Date: 2024-09-23 20:49:19
 * @LastEditors: 姚潘涛
 * @LastEditTime: 2024-09-23 20:58:31
 * @Description: 
 * 
 * Copyright (c) 2024 by pandaman, All Rights Reserved. 
 */
#include "xict_common/utils/perf.h"

namespace xict_common {
    namespace utils {

        std::unordered_map<std::string, std::vector<uint64_t>>
            PerformanceStats::time_records_ = {};

        void Timer::Start() {
            start_time_ = std::chrono::high_resolution_clock::now();
        }

        uint64_t Timer::End(const std::string& msg) {
            end_time_ = std::chrono::high_resolution_clock::now();
            auto elapsed_time =
                std::chrono::duration_cast<std::chrono::nanoseconds>(
                    end_time_ - start_time_)
                    .count();
            ATRACE_F("TIMER [{}] elapsed_time: {} ms", msg,
                     static_cast<double>(elapsed_time) / 1000000.0);

            // start new timer.
            start_time_ = end_time_;
            return elapsed_time;
        }

        TimerWrapper::TimerWrapper(std::string msg) : msg_(std::move(msg)) {
            timer_.Start();
        }

        TimerWrapper::~TimerWrapper() {
            timer_.End(msg_);
        }

        std::string get_full_name(const std::string& full_name) {
            std::size_t end = full_name.find('(');

            if (end == std::string::npos) {
                return full_name;
            }

            std::string new_str = full_name.substr(0, end);
            std::size_t start   = new_str.rfind(' ');

            if (start == std::string::npos) {
                return full_name;
            }

            return new_str.substr(start + 1);
        }

        std::string get_full_name(const std::string& full_name,
                                  const std::string& indicator) {
            return indicator + "_" + get_full_name(full_name);
        }

        void PerformanceStats::AddTime(const std::string& msg, uint64_t time) {
            time_records_[msg].push_back(time);
        }

        double PerformanceStats::GetAverageTime(const std::string& msg) {
            // Check if the message exists.
            if (time_records_.find(msg) == time_records_.end()) {
                return 0;
            }
            // Calculate the average.
            double sum = 0;
            for (auto& time : time_records_[msg]) {
                sum += time;
            }
            return sum / time_records_[msg].size();
        }

        void PerformanceStats::PrintStats(const std::string& msg) {
            // Check if the message exists.
            if (time_records_.find(msg) == time_records_.end()) {
                return;
            }
            // Calculate the average.
            double sum = 0;
            for (auto& time : time_records_[msg]) {
                sum += time;
            }
            double avg = sum / time_records_[msg].size();
            // Calculate the standard deviation.
            double variance = 0;
            for (auto& time : time_records_[msg]) {
                variance += (time - avg) * (time - avg);
            }
            variance /= time_records_[msg].size();
            double std_dev = std::sqrt(variance);
            // Print the statistics.
            ATRACE_F("STATS [{}]: Average: {:.3f} ms, Std Dev: {:.3f} ms", msg,
                     avg / 1000000.0, std_dev / 1000000.0);
        }

    }   // namespace util
}   // namespace xict_common
